﻿using System.Diagnostics;
using System.Net;
using System.Net.Sockets;

using BodaNetCommunications.Cores;
using BodaNetCommunications.Utilities.Locks;
using BodaNetCommunications.Utilities.Results;

namespace BodaNetCommunications.FinsComs
{
    public class CommUnitFins : ICommUnit
    {
        private Socket _socket;

        public int ConnectTimeout { get; set; } = 1000;

        public bool IsConnected
        {
            get
            {
                return _socket != null && !(!_socket.Connected || _socket.Poll(200, SelectMode.SelectRead) && _socket.Available == 0);
            }
        }


        private int _readTimeout = 1000;
        public int ReadTimeout
        {
            get { return _readTimeout; }
            set
            {
                _readTimeout = value;
                if (_socket != null)
                    _socket.ReceiveTimeout = value;
            }
        }

        private string IP { get; set; }
        public int Port { get; set; }

        public EndPoint? LocalEndPoint { get => _socket?.LocalEndPoint; }

        private bool flag = false;

        /// <summary>
        /// 交互的混合锁
        /// </summary>
        protected SimpleHybirdLock _interactiveLock;      // 一次正常的交互的互斥锁


        public CommUnitFins(string ip, int port)
        {
            _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            _socket.ReceiveTimeout = ReadTimeout;
            IP = ip;
            Port = port;
            _interactiveLock = new SimpleHybirdLock();
        }

        public void Close()
        {
            flag = false;
            if (_socket != null)
            {
                _socket.Dispose();
            }
        }

        private ManualResetEvent _timeoutObject = new ManualResetEvent(false);
        private bool _connectState = false;

        public BodaResult<bool> Open(int timeout)
        {
            BodaResult<bool> result = new BodaResult<bool>()
            {
                IsSuccess = true
            };
            try
            {
                Stopwatch stopwatch = new Stopwatch();
                stopwatch.Start();
                while (stopwatch.ElapsedMilliseconds < timeout)
                {
                    if (_socket != null && !(!_socket.Connected || _socket.Poll(200, SelectMode.SelectRead) && _socket.Available == 0))
                    {
                        result.IsSuccess = true;
                        return result;
                    }
                    try
                    {
                        _socket?.Close();
                        _socket?.Dispose();
                        _socket = null;

                        _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                        _socket.ReceiveTimeout = ReadTimeout;
                        _socket.BeginConnect(IP, Port, callback =>
                        {
                            _connectState = false;
                            try
                            {
                                var cbSocket = callback.AsyncState as Socket;
                                if (cbSocket != null)
                                {
                                    _connectState = cbSocket.Connected;

                                    if (cbSocket.Connected)
                                        cbSocket.EndConnect(callback);

                                }
                            }
                            catch (Exception ex)
                            {
                                result.IsSuccess = false;
                                result.Message = ex.Message;
                            }
                            _timeoutObject.Set();
                        }, _socket);
                        _timeoutObject.WaitOne(ConnectTimeout, false);
                        if (_connectState)
                        {
                            result.IsSuccess = true;
                            break;
                        }
                    }
                    catch (SocketException ex)
                    {
                        if (ex.ErrorCode == 10060)
                        {
                            result.IsSuccess = false;
                            result.Message = ex.Message;
                            return result;
                        }
                    }
                    catch (Exception) { }
                }
                if (_socket == null || !_socket.Connected || _socket.Poll(200, SelectMode.SelectRead) && _socket.Available == 0)
                {
                    result.IsSuccess = false;
                    result.Message = "网络连接失败";
                    return result;
                }
            }
            catch (Exception ex)
            {
                result.IsSuccess = false;
                result.Message = ex.Message;
            }
            return result;
        }

        /// <summary>
        /// 这个方法需要调整
        /// </summary>
        /// <param name="req"></param>
        /// <returns></returns>
        public BodaResult<byte> SendAndReceive(List<byte> req, int receiveLen = 1024, int errorLen = 0)
        {
            BodaResult<byte> result = new BodaResult<byte>();

            _interactiveLock.Enter();
            try
            {
                _socket.Send(req.ToArray(), 0, req.Count, SocketFlags.None);

                byte[] headerBytes = new byte[8];
                int readLeng = _socket.Receive(headerBytes, 0, 8, SocketFlags.None);// 卡线程
                if (readLeng == 0)
                {
                    result.IsSuccess = false;
                    result.Message = "未接收到响应数据";
                    return result;
                }

                // 获取整个报文的字节数
                int lastLen = BitConverter.ToInt32(new byte[] { headerBytes[7], headerBytes[6], headerBytes[5], headerBytes[4] });

                byte[] pduBytes = new byte[lastLen];
                readLeng = _socket.Receive(pduBytes, 0, lastLen, SocketFlags.None);
                if (readLeng == 0)
                {
                    result.IsSuccess = false;
                    result.Message = "未接收到响应数据";
                    return result;
                }

                result.Datas.AddRange(headerBytes);
                result.Datas.AddRange(pduBytes);
            }
            catch (Exception ex)
            {
                result.IsSuccess = false;
                result.Message = ex.Message;
            }
            finally
            {
                _interactiveLock.Leave();
            }

            return result;
        }



        public BodaResult<byte> ReceiveMsg(int timeout = 2000, int bytesLen = 1024)
        {
            throw new NotImplementedException();
        }


        public void SendAsync(List<byte> reqBytes, Action<BodaResult<byte>> callback)
        {
            throw new NotImplementedException();
        }

        public BodaResult SendMsgc(byte[] bytes, int timeout = 1500)
        {
            throw new NotImplementedException();
        }
    }
}
